#pragma once
#include <array>
#include <bitset>
#include <cassert>
#include <memory>
#include <unordered_map>
#include <vector>

#include "Containers/SparseSet.h"


namespace ecs
{
// 一个简单的类型别名
using Entity = std::uint32_t;
// 定义Entity的最大数量
const Entity MAX_ENTITIES = 50'000;
using ComponentId         = std::uint8_t;

// 定义Component的最大数量
const ComponentId MAX_COMPONENTS = 32;

// bool[MAX_COMPONENTS]
using Signature = std::bitset<MAX_COMPONENTS>;

// Source: https://gist.github.com/Lee-R/3839813
constexpr std::uint32_t fnv1a_32(char const* s, std::size_t count)
{
    return ((count ? fnv1a_32(s, count - 1) : 2166136261u) ^ s[count]) * 16777619u; // NOLINT (hicpp-signed-bitwise)
}

constexpr std::uint32_t operator "" _hash(char const* s, std::size_t count)
{
    return fnv1a_32(s, count);
}
// Events
using EventId = std::uint32_t;
using ParamId = std::uint32_t;

#define METHOD_LISTENER(EventType, Listener)                                                       \
    EventType, std::bind(&Listener, this, std::placeholders::_1)
#define FUNCTION_LISTENER(EventType, Listener)                                                     \
    EventType, std::bind(&Listener, std::placeholders::_1)

// TODO: Make these easier to define and use (macro?)
// TODO: Add some kind of enforcement/automation that a SetParam type and a GetParam type match

namespace Events::Window
{
const EventId QUIT    = "Events::Window::QUIT"_hash;
const EventId RESIZED = "Events::Window::RESIZED"_hash;
const EventId INPUT   = "Events::Window::INPUT"_hash;
} // namespace Events::Window

namespace Events::Window::Input
{
const ParamId INPUT = "Events::Window::Input::INPUT"_hash;
}

namespace Events::Window::Resized
{
const ParamId WIDTH  = "Events::Window::Resized::WIDTH"_hash;
const ParamId HEIGHT = "Events::Window::Resized::HEIGHT"_hash;
} // namespace Events::Window::Resized
} // namespace ecs